<?php
/**
 * APP_PATH的规范文件路径格式
 */
define('VAR_APPPATH', 1);
/**
 *当前函数库的插件名称
 */
define('VAR_GHXTD', 2);
/**
 *帖子扩展表的表名,不含前缀
 */
define('VAR_THREADEXT_TB', 3);
/**
 *帖子标志表的表名,不含前缀
 */
define('VAR_POSTFLAG_TB', 4);
/**
 *标签表的表名,不含前缀
 */
define('VAR_LABEL_TB', 5);
/**
 *标签记录表的表名,不含前缀
 */
define('VAR_LABELOG_TB', 6);
/**
 *ghx_threadext配置文件的文件路径
 */
define('VAR_GHXTD_CFGPATH', 7);
/**
 *表的字段数据,传入VAR_TABLE_COLUMNS获取,$param指定表名
 */
define('VAR_TABLE_COLUMNS', 8);
/**
 * 数据表的近似最大ID列表 approximation Max id list
 */
define('VAR_APPR_MAXID', 9);
/**
 * 取数据表的主键字段名
 */
define('VAR_TABLE_PRI_KEY', 10);
/**
 * 取数据表的标题字段名
 */
define('VAR_TABLE_FIELD_TITLE', 11);
/**
 * 取数据表的内容(简介)字段名
 */
define('VAR_TABLE_FIELD_INFO', 12);
/**
 * 获取所有数据表的表名,如果指定了附加参数,则以此参数为筛选正则式,如果正则式里有分组,只取最后一分组结果
 */
define('VAR_LIST_DB_TABLES', 13);
/**
 * 模板文件目录,附加参数为类型名,如Thread,Post
 */
define('VAR_VIEW_TEMPLATE_LIST',14);
/**
 * Class CacheAtom 缓存原子,缓存的基本单位
 * 警告:CacheType的[延后保存]只能应用在频繁修改的场景下,否则将得不偿失
 */
class CacheAtom  implements JsonSerializable {
    /**
     * @var string 名称,主键名,包含GhxCache的键前缀,但不包含系统的缓存键前缀
     */
    public $Key;
    /**
     * @var mixed 值,外部不可以直接读写
     */
    protected $Val;
    /**
     * @var mixed 附加的键值对,键名超过32字节长时md5()处理
     */
    protected $AddiKV;
    /**
     * @var integer 到期时间,0为永不过期
     */
    public $Life;
    /**
     * @var integer 浮标,0为不设置,不使用
     */
    public $Buoy;
    /**
     * @var string|int 针对$life或者$buoy而保存的数据,只能初始化,不可以直接访问
     */
    protected $Anchor;
    /**
     * @var int 缓存方式,0:xn缓存;-1:内存;1:[延后保存]之替换;2:[延后保存]之累加,初始值为0,非延后保存状态
     */
    public $CacheType;
    /**
     * @var integer 时间戳
     */
    public $Timestamp;
    /**
     * @var int 修改时间,用于延后保存时与原Timestamp对比,默认值为0
     */
    public $EditTime;
    /**
     * @var array 要被序列化的变量名
     */
    protected static $SerializeVars = array('Key','Val','AddiKV','Life','Buoy','Anchor','Timestamp');

    /**
     * CacheAtom constructor. 创建缓存的基本单位
     * @param string $key 缓存名称,完整键名,可以暂时为空
     * @param mixed $val 值
     * @param int $life 有效期,可以是时间格式和生存秒数,0为不设置
     * @param mixed $buoy 浮标,null为不设置
     * @param int $timestamp 从数据库读取出来的时间戳,0为新值,非数据库原有之值
     * @param int $cache_type 缓存方式,0:xn缓存;-1:内存;1:[延后保存]之替换;2:[延后保存]之累加,初始值为0,非延后保存状态
     * @param mixed $anchor 用于Buoy的锚,主要用于FillUnserializeJsonData(),从XN缓存读取出来后构造成对象
     */
    public function __construct(string $key,$val,$life,$buoy=null,int $timestamp=0,int $cache_type=0,$anchor=null){
        if(strlen($key)>32)
            $key = GhxCache::getInstance()->Crc32Key($key);
        $this->Key = $key;//可以暂时为空
        $this->Val = &$val;
        $this->Life = 0;
        $this->Buoy = null;
        $this->AddiKV = array();
        $this->CacheType = $cache_type;
        $this->Timestamp = $timestamp;
        $this->EditTime = 0;
        if(!empty($life)){//过期时间
            if(strpos($life,':')>0){
                $t = strtotime($life);
                if($t !== false)
                    $this->Life = $t;
            }
            if($this->Life==0){
                $this->Life = time()+(int)$life;
            }
        }
        if(!empty($buoy)){//浮标
            if(empty($anchor))
                $this->Anchor = $buoy;
            else{
                $this->Anchor = $anchor;
            }
            if(is_string($buoy) && file_exists($buoy)){
                $this->Buoy = filemtime($buoy);
                $this->Anchor = 'file://'.$buoy;
            }
            else
                $this->Buoy = $buoy;
        }
    }

    /**
     * 检查初始条件是否有效
     * @param null $buoy 对比浮标值
     * @param int $errorCode 获取详细的错误码:负数表示出错,0为无错;-1:参数错误,-2:存储体不存在或者键名为空,-3:文件修改时间读取错误,-4:已经过期,-5:浮标已经被修改
     * @return bool
     */
    public function check_valid($buoy = null, &$errorCode = 0)
    {
        $ret = true;
        $errorCode = 0;
        if ($this->Life != 0) {
            if (time() > $this->Life) {
                $errorCode = -4;
                $ret = false;
            }
        }
        if ($this->Buoy !== null) {
            if ($buoy !== null) {
                if ($buoy != $this->Buoy) {
                    $errorCode = -5;
                    $ret = false;
                }
            } else {
                if (!empty($this->Anchor) && is_string($this->Anchor) && substr($this->Anchor, 0, 7) == 'file://') {
                    $curCTime = filemtime(substr($this->Anchor, 7));
                    if ($curCTime == false) {
                        $errorCode = -3;
                        $ret = false;
                    } elseif ($curCTime != $this->Buoy) {
                        $errorCode = -5;
                        $ret = false;
                    }
                }
                else{
                    $errorCode = -5;
                    $ret = false;
                }
            }
        }
        if($ret){
            if(empty($this->Key)){
                $ret = false;
                $errorCode = -2;
            }

        }
        return $ret;
    }

    /**
     * 获取基本缓存原子的值,如果无效返回null
     * @param string|null $name val/value 对应Val,kv/addi 对应AddiKV,默认为val
     * @param mixed $buoy 浮标对比值
     * @param string $sub_key 要取的附加键名
     * @param int &$checkCode 负数表示出错,0为无错;-1:参数错误,-2:存储体不存在或者键名为空,-3:文件修改时间读取错误,-4:已经过期,-5:浮标已经被修改
     * @return mixed|null
     */
    public function &get_value(string $name='val',$buoy=null,string $sub_key='',int &$checkCode=0){
        $xname = strtolower($name);
        $retnull = null;
        if($xname == 'val' || $xname == 'value'){
            if($this->check_valid($buoy,$checkCode))
                return $this->Val;
            else
                return $retnull;
        }
        elseif($xname == 'kv' || $xname == 'addi'){
            if(!empty($sub_key)) {
                if(strlen($sub_key)>32) $sub_key = md5($sub_key);
                if (isset($this->AddiKV[$sub_key]) && $this->check_valid($buoy)) {
                    return $this->AddiKV[$sub_key];
                }
            }
        }
        return $retnull;
    }
    public function &__get($property_name){
        $ret = &$this->get_value($property_name);
        return $ret;
    }
    public function __set($property_name,$value){
        $xname = strtolower($property_name);
        $ret = false;
        if($xname == 'val' || $xname == 'value'){
            $is_diff = false;
            if(is_array($value) != is_array($this->Val))
                $is_diff = true;
            else{
                $diff_assoc = &array_diff_assoc_recursive($value,$this->Val);
                $is_diff = empty($diff_assoc);
            }
            if($is_diff) {
                $ret = true;
                $oldV = $this->Val;//先保存
                $this->Val = &$value;
                if ($this->CacheType == 1 || $this->CacheType == 2) {
                    $this->EditTime = msectime();
                }
                elseif ($this->CacheType == 0) {//直接保存到缓存中:
                    $ret = $this->SaveToCache();
                }
                if(!$ret){
                    $this->Val = &$oldV;//恢复原值
                }
            }
        }
        return $ret;
    }

    /**
     * 将当前对象保存到缓存中,延后保存的不会执行操作
     * @param array|CacheAtom $cache_old 旧有的缓存原子值,默认为null,表示到XN缓存中读取
     * @return bool
     */
    public function SaveToCache(&$cache_old=null)
    {
        $ret = false;
        $is_valid = $this->check_valid();
        $lifeV = $this->Life;
        if ($lifeV > 0)
            $lifeV = $lifeV - time();
        $optv = 0;//操作代号
        if ($this->CacheType == 0) {
            $thatCacheAtom = null;
            if($cache_old !== null){
                if(is_array($cache_old)){
                    $thatCacheAtom = CacheAtom::FillUnserializeJsonData($cache_old);
                }
                elseif($cache_old instanceof CacheAtom){
                    $thatCacheAtom = $cache_old;
                }
            }
            else{
                $thatval = cache_get($this->Key);
                if ($thatval !== null && $thatval !== false && is_array($thatval)) {
                    $thatCacheAtom = CacheAtom::FillUnserializeJsonData($thatval);
                }
            }
            if ($thatCacheAtom !== null) {
                if ($thatCacheAtom === false || $thatCacheAtom->Timestamp < $this->EditTime) {
                    if ($is_valid)
                        $optv = 1;
                    else
                        $optv = -1;
                }
            } else {
                if ($is_valid) $optv = 1;
            }

        }
        //执行操作:
        if($optv != 0) {
            if ($this->EditTime != 0) {
                $this->Timestamp = $this->EditTime;
            }
            if ($this->Timestamp == 0)
                $this->Timestamp = msectime();
            if ($optv == 1)
                $ret = cache_set($this->Key, $this, $lifeV);
            elseif ($optv == -1)
                $ret = cache_delete($this->Key);
        }
        return $ret;
    }

    /**
     * 设置附加键值数据
     * @param string $key
     * @param $value
     */
    public function set_addi(string $key,$value){
        if(strlen($key)>32) $key = md5($key);
        $this->AddiKV[$key] = $value;
    }
    public function __sleep(){
        return self::$SerializeVars;
    }
    public function __wakeup(){
        $this->CacheType = 0;
        $this->EditTime = 0;
    }
    public function jsonSerialize (){
        $ret = array();
        foreach (self::$SerializeVars as $var){
            $ret[$var] = $this->$var;
        }
        return $ret;
    }

    /**
     * 把JSON反序列化后的数组转化为CacheAtom对象
     * @param array $arr
     * @return CacheAtom|false
     */
    public static function FillUnserializeJsonData(array &$arr) {
        $obj = false;
        if(!empty($arr)){
            $obj = new CacheAtom($arr['Key'],$arr['Val'],$arr['Life'],$arr['Buoy'],$arr['Timestamp'],0,$arr['Anchor']);
            $obj->__wakeup();
        }
        return $obj;
    }
}

/**
 * Class GhxCache 缓存扩展类
 * 功能:变量静态化,对XN缓存的包装
 */
class GhxCache
{
    /**
     * @var GhxCache 单实例
     */
    static private $instance=null;
    /**
     * @var array 缓存的数组,array({key}=>{CacheAtom}...},key不含键前缀
     */
    static protected $cache_arr = array();
    /**
     * @var array 共用变量数组
     */
    protected $share_vars;
    /**
     * @var string 缓存前缀,默认为ghx~
     */
    protected $CachePrefix;
    /**
     * @var int 最大的缓存键名长度
     */
    protected $MaxCacheKeyLen;
    private function __construct($cache_prefix){//防止直接创建对象
        $this->CachePrefix = ($cache_prefix===null?'':$cache_prefix);
        $PrefixLen = strlen($this->CachePrefix);
        if($PrefixLen > 10){
            $this->CachePrefix = substr($cache_prefix,-5);
            $PrefixLen = 5;
        }
        $this->MaxCacheKeyLen = 32;
        if(!empty($this->CachePrefix)){
            $this->MaxCacheKeyLen -= $PrefixLen;
        }
        $xncache = $_SERVER['cache'];
        if(!empty($xncache)){
            $this->MaxCacheKeyLen -= strlen($xncache->cachepre);
        }
        $this->share_vars = array();
    }
    function __destruct()
    {
        //处理延后保存:
        if (!empty(self::$cache_arr)) {
            foreach (self::$cache_arr as $key => &$val) {
                if ($val instanceof CacheAtom) {
                    if($val->CacheType < 1) continue;//不需要保存到缓存
                    $this->SaveCache($val,null,true);//立即保存
                }
            }
        }
    }
    private function __clone(){//防止克隆对象
    }

    /**
     * 获取GhxCache的唯一实例
     * @param string $cache_prefix 缓存键名前缀,默认为null,表示到配置中[CacheKeySecondary]加载,如果配置不存在设为ghx~
     * @return GhxCache
     */
    static public function getInstance($cache_prefix=null){
        if (self::$instance === null) {
            if($cache_prefix==null){
                $reger = '#^.+?[\/\\\\]plugin_([\w\-]+)_model_[^\/\\\\]+$#i';
                $mcs = array();
                $plugin_ghxtd_name = 'ghx_threadext';
                if (preg_match($reger, __FILE__, $mcs) > 0) {
                    $plugin_ghxtd_name = $mcs[1];
                }
                $apppath_std = (DIRECTORY_SEPARATOR == '/' ? str_replace('\\', DIRECTORY_SEPARATOR, APP_PATH) : str_replace('/', DIRECTORY_SEPARATOR, APP_PATH));
                $dir = $apppath_std . 'plugin' . DIRECTORY_SEPARATOR . $plugin_ghxtd_name . DIRECTORY_SEPARATOR;
                $full_path = $dir . 'conf.json';
                $cfg = xn_json_decode(file_get_contents($full_path));
                if(!empty($cfg) && isset($cfg['CacheKeySecondary'])){
                    $cache_prefix = $cfg['CacheKeySecondary'];
                }
                if(empty($cache_prefix))
                    $cache_prefix = 'ghx~';
            }
            self::$instance = new self($cache_prefix);
        }
        return self::$instance;
    }

    /**
     * 从XN缓存读取指定值到$cache_arr,并返回该值
     * @param string $key 要读取的键名,不包含前缀(如果有,会删除)
     * @return CacheAtom|false 失败返回false
     */
    public function &ReadCache(string $key){
        $ret = false;
        if(!empty($key)){
            $key= $this->Crc32Key($key);
            $v = cache_get($this->CachePrefix.$key);
            if($v !== null && $v !== false){
                $v2 = CacheAtom::FillUnserializeJsonData($v);
                if($v2 !== false) {
                    if(empty($v2->Key)){
                        $v2->Key = $this->CachePrefix.$key;
                    }
                    self::$cache_arr[$key] = &$v2;
                    $ret = $v2;
                }
            }
        }
        return $ret;
    }

    /**
     * 把CacheAtom保存到缓存中,$key不为空时,更新到self::$cache_arr
     * @param CacheAtom $value
     * @param string|null $key 不为空时会进行Crc32Key()处理并且更新到self::$cache_arr,为null时,只进行保存操作
     * @param bool $just_save 是否立即保存,当CacheType=0时,无论是否都将保存,CacheType=1|2时才会有所体现,这是针对延时保存的选项
     * @return bool
     */
    public function SaveCache(CacheAtom $value, string $key = null, bool $just_save = false)
    {
        $ret = false;
        $cacheType = $value->CacheType;
        $is_valid = $value->check_valid();
        $optv = 0;//不操作
        $lifeV = $value->Life;
        if ($lifeV > 0)
            $lifeV = $lifeV - time();
        if(!empty($key)){
            $key = $this->Crc32Key($key);
        }
        if($is_valid && empty($value->Key)){
            $value->Key = $this->CachePrefix.$key;
        }
        if ($is_valid && !empty($key)) {
            self::$cache_arr[$key] = &$value;
            $ret = true;
        }
        $cache_Key = $value->Key;
        if(strpos($cache_Key,$this->CachePrefix) !== 0){
            $cache_Key = $this->CachePrefix.$cache_Key;
        }
        $Old_Timestamp = $Old_EditTime = null;
        if ($cacheType > -1) {//不需要保存到缓存,跳过
            $thatval = $thatCacheAtom = null;
            $Old_Timestamp = $value->Timestamp;
            $Old_EditTime = $value->EditTime;
            if ($value->EditTime == 0) $value->EditTime = msectime();
            if ($value->Timestamp == 0) $value->Timestamp = $value->EditTime;
            $thatval = cache_get($cache_Key);
            if ($thatval !== null && $thatval !== false && is_array($thatval)) {
                $thatCacheAtom = CacheAtom::FillUnserializeJsonData($thatval);
            }
            if ($cacheType == 0) {
                if ($thatCacheAtom !== null) {
                    if ($thatCacheAtom === false || $thatCacheAtom->Timestamp < $value->EditTime) {
                        if ($is_valid)
                            $optv = 1;
                        else
                            $optv = -1;
                    }
                } else {
                    if ($is_valid) $optv = 1;
                }

            } elseif ($just_save) {
                if ($cacheType == 1) {//没有保存,替换型
                    if ($thatCacheAtom !== null) {
                        if ($thatCacheAtom === false || $thatCacheAtom->Timestamp < $value->EditTime) {
                            if ($is_valid)
                                $optv = 1;
                            else
                                $optv = -1;
                        }
                    } else {
                        if ($is_valid) $optv = 1;
                    }
                } elseif ($cacheType == 2) {//累加型
                    if ($is_valid) {
                        $optv = 1;
                        if ($thatCacheAtom !== null && $thatCacheAtom !== false) {
                            $value->Val += $thatCacheAtom->Val;
                        }
                    }
                }
            }
            //执行操作:
            if ($optv != 0) {
                if ($optv == 1){
                    $ret = cache_set($cache_Key, $value, $lifeV);
                    if(!$ret){
                        unset(self::$cache_arr[$key]);//保存失败,清除脏数据
                    }
                }
                elseif ($optv == -1)
                    $ret = cache_delete($cache_Key);
            } else {
                if ($Old_Timestamp !== null) {
                    $value->Timestamp = $Old_Timestamp;
                    $value->EditTime = $Old_EditTime;
                }
            }
        }
        return $ret;
    }

    /**
     * 获取缓存键名,超过长度时会Crc32处理,不会包含前缀
     * @param string &$key 如果有前缀,会删除掉
     * @return string|false 能返回引用
     */
    public function &Crc32Key(string &$key){
        $ret = false;
        if(!empty($key)){
            if (stripos($key, $this->CachePrefix) === 0) {
                $key = substr($key, strlen($this->CachePrefix));
            }
            if(strlen($key) > $this->MaxCacheKeyLen)
                $ret = 'C'.strval(crc32($key)).strval(crc32(strrev($key)));
            else
                $ret = &$key;
        }
        return $ret;
    }
    /**
     * 获取一个指定键名的缓存
     * @param $propertyName
     * @return CacheAtom|false
     */
    public function __get($propertyName){
        $ret = null;
        static $notCacheKey = array('CachePrefix');
        if(!in_array($propertyName,$notCacheKey)) {
            $propertyName = &$this->Crc32Key($propertyName);
            if (!isset(self::$cache_arr[$propertyName])) {
                $ret = &$this->ReadCache($propertyName);
            } else
                $ret = &self::$cache_arr[$propertyName];
        }
        else{
            if($propertyName == 'CachePrefix'){
                $ret = $this->CachePrefix;//不可引用
            }
        }
        return $ret;
    }
    public function __set($propertyName,$value){
        $ret = false;
        $propertyName = &$this->Crc32Key($propertyName);
        if (($value instanceof CacheAtom) == false){
            $_value = new CacheAtom($this->CachePrefix.$propertyName,$value,3600*12);//默认有效时间:12小时
        }
        else
            $_value = $value;
        $ret = $this->SaveCache($_value,$this->CachePrefix.$propertyName);
        return $ret;
    }

    /**
     * 获取公共变量
     *  share_vars['APPPATH'] :APP_PATH的规范文件路径格式,$param为分隔符
     *  share_vars['plugin_ghxtd_name']:当前函数库的插件名称
     *  share_vars['tbn_THREADEXT']:帖子扩展表的表名,不含前缀
     *  share_vars['tbn_POSTFLAG']:帖子标志表的表名,不含前缀
     *  share_vars['tbn_LABEL']:标签表的表名,不含前缀
     *  share_vars['tbn_LABELOG']:标签记录表的表名,不含前缀
     *  share_vars['path_ghx_cfg']:ghx_threadext配置文件的文件路径
     * @param int $id (表名不含前缀)一般是以VAR_开头的常量
     * @param mixed $param 其它附加参数
     * @param boolean $refresh 是否刷新
     * @return mixed|false
     */
    function &get_share_var(int $id, $param = null, $refresh = false){
        //初始化:
        if ($refresh || !isset($this->share_vars['APPPATH']) || empty($this->share_vars['APPPATH'])) {
            $this->share_vars['APPPATH'] = APP_PATH;
            if ($this->share_vars['APPPATH'][strlen($this->share_vars['APPPATH']) - 1] != DIRECTORY_SEPARATOR)
                $this->share_vars['APPPATH'] = (DIRECTORY_SEPARATOR == '/' ? str_replace('\\', DIRECTORY_SEPARATOR, APP_PATH) : str_replace('/', DIRECTORY_SEPARATOR, APP_PATH));
            $reger = '#^.+?[\/\\\\]plugin_([\w\-]+)_model_[^\/\\\\]+$#i';
            $mcs = array();
            $this->share_vars['plugin_ghxtd_name'] = 'ghx_threadext';
            if (preg_match($reger, __FILE__, $mcs) > 0) {
                $this->share_vars['plugin_ghxtd_name'] = $mcs[1];
            }
            $this->share_vars['tbn_THREADEXT'] = 'threadext';
            $this->share_vars['tbn_POSTFLAG'] = 'postflag';
            $this->share_vars['tbn_LABEL'] = 'label';
            $this->share_vars['tbn_LABELOG'] = 'labelog';
            $threadext_cfg = &get_plugin_config($this->share_vars['plugin_ghxtd_name']);
            if (!empty($threadext_cfg['ThreadextTable'])) $this->share_vars['tbn_THREADEXT'] = $threadext_cfg['ThreadextTable'];
            if (!empty($threadext_cfg['Label']['LabelTable'])) $this->share_vars['tbn_LABEL'] = $threadext_cfg['Label']['LabelTable'];
            if (!empty($threadext_cfg['Label']['LabellogTable'])) $this->share_vars['tbn_LABELOG'] = $threadext_cfg['Label']['LabellogTable'];
            if (!empty($threadext_cfg['PostFlag']['table'])) $this->share_vars['tbn_POSTFLAG'] = $threadext_cfg['PostFlag']['table'];
            $this->share_vars['path_ghx_cfg'] = $this->share_vars['APPPATH'] . 'plugin' . DIRECTORY_SEPARATOR . $this->share_vars['plugin_ghxtd_name'] . DIRECTORY_SEPARATOR . 'conf.json';
        }
        global $conf;

        $ret = false;
        switch ($id) {
            case VAR_APPPATH:
                $ret = &$this->share_vars['APPPATH'];
                if (!empty($param)){
                    if($param != DIRECTORY_SEPARATOR){
                        $retX = str_replace(DIRECTORY_SEPARATOR,$param,$ret);
                        unset($ret);
                        $ret = &$retX;
                    }
                }
                break;
            case VAR_GHXTD:
                $ret = &$this->share_vars['plugin_ghxtd_name'];
                break;
            case VAR_THREADEXT_TB:
                $ret = &$this->share_vars['tbn_THREADEXT'];
                break;
            case VAR_POSTFLAG_TB:
                $ret = &$this->share_vars['tbn_POSTFLAG'];
                break;
            case VAR_LABEL_TB:
                $ret = &$this->share_vars['tbn_LABEL'];
                break;
            case VAR_LABELOG_TB:
                $ret = &$this->share_vars['tbn_LABELOG'];
                break;
            case VAR_GHXTD_CFGPATH:
                $ret = &$this->share_vars['path_ghx_cfg'];
                break;
            case VAR_TABLE_COLUMNS:
                if (!empty($param)) {
                    $ckey = 'TB_Columns_'.$param;
                    $retobj = null;
                    if(!$refresh) $retobj = $this->$ckey;
                    if(empty($retobj) || $retobj->Val==null){
                        $retv = &table_column_list($param, 'COLUMN_NAME,DATA_TYPE');
                        $retobj = new CacheAtom($this->CachePrefix.$ckey,$retv,3600*24*7);//缓存一周
                        $this->$ckey = $retobj;//保存到缓存
                    }
                    if(!empty($retobj)){
                        $ret = $retobj->Val;
                    }
                }
                break;
            case VAR_APPR_MAXID:
                if (!empty($param)) {
                    if(!isset($this->share_vars['appr_maxids']))
                        $this->share_vars['appr_maxids'] = array();
                    if (!isset($this->share_vars['appr_maxids'][$param]) || $refresh || (isset($this->share_vars['appr_maxids'][$param]['times']) && $this->share_vars['appr_maxids'][$param]['times'] > 100)) {
                        $results = array('max'=>0,'times'=>0);
                        $tmpV = db_sql_find_one(GetDBSql($param, '自增列值', $conf['db']['type']));
                        if ($tmpV === false) {
                            //查询主键:
                            $tmpV = $this->get_share_var(VAR_TABLE_PRI_KEY, $param);
                            if ($tmpV != false)
                                $results['max'] = intval(db_maxid($param, $tmpV));
                            else
                                $results['max'] = intval(db_maxid($param, 'id'));
                        } else {
                            $results['max'] = intval(current($tmpV)) - 1;
                        }
                        $this->share_vars['appr_maxids'][$param] = &$results;
                        unset($results);
                    } else {
                        $this->share_vars['appr_maxids'][$param]['times']++;
                    }
                    $ret = &$this->share_vars['appr_maxids'][$param]['max'];
                }
                break;
            case VAR_TABLE_PRI_KEY://取主键字段名
                if (!empty($param)) {
                    $tblog = $this->share_vars['tbn_LABELOG'];
                    $param_cpy = $param;
                    if (stripos($param, $tblog) === 0) $param = $tblog;
                    $ckey = 'TB_Columns';
                    $TB_Columns_ca = $this->TB_Columns;
                    if (empty($TB_Columns_ca) || !isset($TB_Columns_ca->Val[$param]) || $refresh) {
                        $PrimaryKeys = &GetPluginCfgNode('TableFieldDim/PrimaryKeys');
                        if(!empty($TB_Columns_ca)) $tables_columns = $TB_Columns_ca->Val;
                        else $tables_columns = array();
                        if ($refresh) {
                            $tables_columns = $PrimaryKeys;
                        } else {
                            $tables_columns = $tables_columns + $PrimaryKeys;
                        }
                        if (!isset($tables_columns[$param])) {
                            $tmpV = db_sql_find_one(GetDBSql($param_cpy, '主键', $conf['db']['type']));
                            if ($tmpV != false) {
                                $tables_columns[$param] = current($tmpV);
                            }
                        }
                        //保存到缓存中:
                        $TB_Columns_ca = new CacheAtom($this->CachePrefix.$ckey,$tables_columns,3600*24*7);//缓存一周
                        $this->TB_Columns = $TB_Columns_ca;
                    }
                    else
                        $tables_columns = $TB_Columns_ca->Val;
                    $ret = &$tables_columns[$param];
                }
                break;
            case VAR_TABLE_FIELD_TITLE:
                if (!empty($param)) {
                    $TitleFields = &GetPluginCfgNode('TableFieldDim/TitleField');
                    if (!empty($TitleFields)) {
                        $tblog = $this->share_vars['tbn_LABELOG'];
                        if (stripos($param, $tblog) === 0) $param = $tblog;
                        if (isset($TitleFields[$param])) {
                            $ret = &$TitleFields[$param];
                        }
                    }
                }
                break;
            case VAR_TABLE_FIELD_INFO:
                if (!empty($param)) {
                    $InfoFields = &GetPluginCfgNode('TableFieldDim/InfoField');
                    if (!empty($InfoFields)) {
                        $tblog = $this->share_vars['tbn_LABELOG'];
                        if (stripos($param, $tblog) === 0) $param = $tblog;
                        if (isset($InfoFields[$param])) {
                            $ret = &$InfoFields[$param];
                        }
                    }
                }
                break;
            case VAR_LIST_DB_TABLES:
                $gdt_KEY = 'DBAllTables';
                $retobj = $this->DBAllTables;
                $db_tables = null;
                if(!empty($retobj)){
                    $db_tables = $retobj->Val;
                }
                if(empty($db_tables) || $refresh) {
                    $tmpVs = db_sql_find(GetDBSql('*', 'alltables', $conf['db']['type']));
                    if(!empty($tmpVs)){
                        foreach($tmpVs as &$tmpV){
                            $db_tables[] = current($tmpV);
                        }
                    }
                    $this->DBAllTables = new CacheAtom($this->CachePrefix.$gdt_KEY,$db_tables,0,$conf['tmp_path'].'route_index.php');
                }
                if (!empty($param)){
                    $ret = array();
                    foreach($db_tables as &$ptable){
                        $msr = null;
                        if(preg_match($param,$ptable,$msr)>0){
                            //取最后一组:
                            if(count($msr) > 1)
                                $ret[] = $msr[count($msr)-1];
                            else
                                $ret[] = $msr[0];
                        }
                    }
                }
                else
                    $ret = $db_tables;
                break;
            case VAR_VIEW_TEMPLATE_LIST:
                if (!empty($param)) {
                    $ckey = 'view_template_list';
                    $view_template_list = array();
                    if(!$refresh){
                        $retobj = $this->$ckey;
                        if(!empty($retobj)){
                            $view_template_list = &$retobj->Val;
                            if(isset($view_template_list[$param])){
                                $ret =  &$view_template_list[$param];
                            }
                        }
                    }
                    if ($refresh || empty($view_template_list) || !isset($view_template_list[$param]) || $view_template_list[$param] === NULL) {
                        $ViewTemplateCfg = &GetPluginCfgNode('ViewTemplate');
                        if (!empty($ViewTemplateCfg) && $ViewTemplateCfg['enable'] > 0) {
                            $nodeName = NULL;
                            $type2 = strtolower($param);
                            switch ($type2) {
                                case 'thread':
                                    $nodeName = 'Thread';
                                    break;
                                case 'post':
                                    $nodeName = 'Post';
                                    break;
                                default:
                                    break;
                            }
                            unset($type2);
                            $CurViewTemplateCfg = NULL;
                            if ($nodeName != NULL)
                                $CurViewTemplateCfg = &$ViewTemplateCfg[$nodeName];
                            if (!empty($CurViewTemplateCfg)) {
                                $include_path = $this->share_vars['APPPATH'] . 'plugin' . DIRECTORY_SEPARATOR . $this->share_vars['plugin_ghxtd_name'] . DIRECTORY_SEPARATOR.'inc'.DIRECTORY_SEPARATOR;
                                $appath_len = strlen($this->share_vars['APPPATH']);
                                if (isset($CurViewTemplateCfg['ViewTemplateList'])) {
                                    $view_template_list[$param] = $CurViewTemplateCfg['ViewTemplateList'];
                                    $delcounts = 0;
                                    foreach ($CurViewTemplateCfg['ViewTemplateList'] as $tplN => &$tplps) {
                                        foreach($tplps as $tpli => &$tplp){
                                            if (!is_file($tplp)){
                                                $tplp = $include_path . $tplp;
                                                if (is_file($tplp)){
                                                    $tplp = substr($tplp,$appath_len);
                                                    $view_template_list[$param][$tplN][$tpli] = $tplp;
                                                }

                                            }
                                            if (!is_file($tplp)) {
                                                unset($view_template_list[$param][$tplN][$tpli]);
                                                $delcounts++;
                                            }
                                        }
                                        if(empty($view_template_list[$param][$tplN]))
                                            unset($view_template_list[$param][$tplN]);
                                    }
                                    unset($tplp,$tplps);
                                    //检测反刍
                                    if ($delcounts > 0)
                                        $CurViewTemplateCfg['ViewTemplateList'] = $view_template_list[$param];
                                } else
                                    $view_template_list[$param] = array();//重置
                                if (!empty($CurViewTemplateCfg['AutoSearchPath']) && is_dir($CurViewTemplateCfg['AutoSearchPath']) && !empty($CurViewTemplateCfg['CaptionMatchReg'])) {
                                    $allfiles = &get_filenames_ci3($CurViewTemplateCfg['AutoSearchPath'], true);
                                    if (!empty($allfiles)) {
                                        $viewpath_separator_type = strpos($CurViewTemplateCfg['AutoSearchPath'],'\\');
                                        foreach ($allfiles as $fp) {
                                            $fctxt = file_get_contents($fp);
                                            $matches = null;
                                            if (@preg_match($CurViewTemplateCfg['CaptionMatchReg'], $fctxt, $matches) > 0) {
                                                if (isset($matches['caption']) && !empty($matches['caption'])) {
                                                    $fp = substr($fp,$appath_len);
                                                    if($viewpath_separator_type !== FALSE) $fp = str_replace('/','\\',$fp);
                                                    else $fp = str_replace('\\','/',$fp);
                                                    $_caption = $matches['caption'];
                                                    if (!isset($view_template_list[$param][$_caption])) $view_template_list[$param][$_caption] = array();
                                                    $_files = &$view_template_list[$param][$_caption];
                                                    if (!in_array($fp, $_files,true)) $_files[] = &$fp;
                                                    //include file:
                                                    if(!empty($CurViewTemplateCfg['IncludeMatchReg'])){
                                                        if (@preg_match($CurViewTemplateCfg['IncludeMatchReg'], $fctxt, $matches) > 0){
                                                            $_includes = $matches['include'];
                                                            $_includes = preg_split('/[,;\|]+/',$_includes,-1,PREG_SPLIT_NO_EMPTY);
                                                            foreach($_includes as &$_include){
                                                                if(!is_file($_include)){//没有指定目录:
                                                                    $_include = $include_path.$_include;
                                                                }
                                                                if (is_file($_include)){
                                                                    $_include = substr($_include,$appath_len);//去除前缀
                                                                    if(!in_array($_include, $_files,true)){
                                                                        $_files[] = &$_include;
                                                                    }
                                                                }
                                                                unset($_include);
                                                            }
                                                        }
                                                    }
                                                    unset($_files,$fp);
                                                }
                                            }
                                        }
                                    }
                                }
                                $this->$ckey = new CacheAtom($this->CachePrefix.$ckey,$view_template_list,3600*24*7,$conf['tmp_path'].'route_index.php');
                            }
                            if(isset($view_template_list[$param])) $ret =  &$view_template_list[$param];
                        }
                    }
                }
                break;
            default:
                break;
        }
        return $ret;
    }
}